// +build sw64

package errors

import (
        "reflect"
)

func Unwrap(err error) error {
        u, ok := err.(interface {
                Unwrap() error
        })
        if !ok {
                return nil
        }
        return u.Unwrap()
}

func SelfIs(err, target error) bool {
        if target == nil {
                return err == target
        }

        isComparable := reflect.TypeOf(target).Comparable()
        for {
                if isComparable && err == target {
                        return true
                }
                if x, ok := err.(interface{ SelfIs(error) bool }); ok && x.SelfIs(target) {
                        return true
                }
                // TODO: consider supporting target.Is(err). This would allow
                // user-definable predicates, but also may allow for coping with sloppy
                // APIs, thereby making it easier to get away with them.
                if err = Unwrap(err); err == nil {
                        return false
                }
        }
}

func As(err error, target interface{}) bool {
        if target == nil {
                panic("errors: target cannot be nil")
        }
        val := reflect.ValueOf(target)
        typ := val.Type()
        if typ.Kind() != reflect.Ptr || val.IsNil() {
                panic("errors: target must be a non-nil pointer")
        }
        if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
                panic("errors: *target must be interface or implement error")
        }
        targetType := typ.Elem()
        for err != nil {
                if reflect.TypeOf(err).AssignableTo(targetType) {
                        val.Elem().Set(reflect.ValueOf(err))
                        return true
                }
                if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
                        return true
                }
                err = Unwrap(err)
        }
        return false
}

var errorType = reflect.TypeOf((*error)(nil)).Elem()
